﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Runtime.InteropServices;

namespace RemotingTesting
{
    static class Program
    {
        static System.Threading.Mutex _m;

        // Get a handle to an application window.
        //[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
        //public static extern IntPtr FindWindow(string lpClassName,
        //    string lpWindowName);

        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
        public const int SW_SHOW = 5;

        // Activate an application window.
        [DllImport("USER32.DLL")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        static extern bool IsZoomed(IntPtr hWnd);

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            bool ok;
            _m = new System.Threading.Mutex(true, "RemotingTestingMutexHaHaHaHa09329823333", out ok);

            //if (!ok)
            //{
            //    //MessageBox.Show("Another instance is already running.");
            //    return;
            //}

            //Process priorProcess = PriorProcess();
            Process process = PriorProcess();
            if (process != null)
            {
                if (process.MainWindowHandle != IntPtr.Zero)
                {
                    IntPtr ptr = process.MainWindowHandle;

                    bool isMaximized = IsZoomed(ptr);
                    if (!isMaximized)
                    {
                        ShowWindow(ptr, SW_SHOW);
                    }
                    SetForegroundWindow(ptr);
                }

                return;
            }
            
            //if (priorProcess != null)
            if (!ok)
            {
                IpcChannel chan = new IpcChannel();

                // Register as client for remote object.
                System.Runtime.Remoting.WellKnownClientTypeEntry remoteType =
                    new System.Runtime.Remoting.WellKnownClientTypeEntry(
                        typeof(RemoteObject),
                        "ipc://localhost:9090/RemoteObject.rem");
                System.Runtime.Remoting.RemotingConfiguration.
                    RegisterWellKnownClientType(remoteType);

                // Create an instance of the remote object.
                RemoteObject service = new RemoteObject();
                //service.SendMessage("this is a test");

                return;
            }

            {
                IpcChannel chan = new IpcChannel("localhost:9090");
                ChannelServices.RegisterChannel(chan, false);

                // Expose an object for remote calls.
                System.Runtime.Remoting.RemotingConfiguration.
                    RegisterWellKnownServiceType(
                        typeof(RemoteObject), "RemoteObject.rem",
                        System.Runtime.Remoting.WellKnownObjectMode.Singleton);

                RemoteObject m_RemoteObject = (RemoteObject)
                    Activator.GetObject(typeof(RemoteObject),
                    "ipc://localhost:9090/RemoteObject.rem");

                //m_RemoteObject.MainForm = mainForm;
            }

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            mainForm = new Form1();
            Application.Run(mainForm);

            //GC.KeepAlive(_m);                // important!
        }

        static Form1 mainForm;
        static void m_RemoteObject_MessageSent(string xml)
        {
            //throw new NotImplementedException();
            bool test = true;
        }

        public static Process PriorProcess()
        // Returns a System.Diagnostics.Process pointing to
        // a pre-existing process with the same name as the
        // current one, if any; or null if the current process
        // is unique.
        {
            Process curr = Process.GetCurrentProcess();
            Process[] procs = Process.GetProcessesByName(curr.ProcessName);
            foreach (Process p in procs)
            {
                if ((p.Id != curr.Id) &&
                    (p.MainModule.FileName == curr.MainModule.FileName))
                    return p;
            }
            return null;
        }

        // Remote object. 
        public class RemoteObject : MarshalByRefObject
        {
            // http://www.codeproject.com/Articles/4938/Remote-methods-and-events-in-C

            private int callCount = 0;
            public delegate void MessageHandler(string xml);
            // event declaration
            public event MessageHandler MessageSent;

            //public PhonesXmlEditor.MainForm MainForm { get; set; }

            //public void SendMessage(string xml)
            //{
            //    MessageSent(xml);
            //}

            public int GetCount()
            {
                Console.WriteLine("GetCount has been called.");
                callCount++;
                return (callCount);
            }
        }
    }
}
